﻿using System.Xml.Linq;
using IcicleFramework.Components.Actions.ActionEffects;
using IcicleFramework.Entities;
using Microsoft.Xna.Framework;

namespace IcicleFramework.Components.Actions
{
    public abstract class BaseAction : IAction
    {
        #region Properties

        public string Name { get; set; }

        public ActionState State { get; protected set; }

        public IActionEffect ActionEffect { get; set; }

        public IActionComponent Parent { get; set; }

        public IGameObject Target { get; set; }

        public bool PerformingActions { get; protected set; }

        protected bool PerformingActionsBeforePause { get; set; }

        public bool ContinuousActions { get; protected set; }

        public int NumActionsPerformedSinceStarted { get; protected set; }

        protected IActionData ActionData { get; set; }

        public bool Paused { get; protected set; }

        public IGameObject ParentGameObject
        {
            get { return Parent.Parent; }
        }

        #endregion


        #region Events

        public event OnStartedPerformingActionsHandler OnStartedPerformingActions;

        public event OnStartedPerformingActionsHandler OnPerformingAction;

        public event OnStoppedPerformingActionsHandler OnStoppedPerformingActions;

        #endregion


        #region Constructors

        protected BaseAction() { }

        protected BaseAction(BaseAction old)
        {
            Name = old.Name;
        }

        #endregion


        public virtual void Initialize() { }

        public virtual void PostInitialize() { }

        protected virtual void ChangeState()
        {
            switch (State)
            {
                case ActionState.Idle:
                    State = ActionState.Charging;
                    break;

                case ActionState.Charging:
                    State = ActionState.PerfomingAction;
                    Execute();
                    break;

                case ActionState.PerfomingAction:
                    State = ActionState.Idle;
                    break;
            }
        }

        protected virtual void Execute()
        {
            NumActionsPerformedSinceStarted++;

            if (ActionEffect != null)
            {
              //  IActionComponent Target.GetComponent<IActionComponent>()
            }
            
            if (OnPerformingAction != null)
            {
                OnPerformingAction(this, Target, ContinuousActions);
            }

            if (!ContinuousActions)
            {
                Stop();
            }
        }

        public virtual void Execute(IGameObject target, IActionData data = null, bool continuous = false)
        {
            Target = target;
            ContinuousActions = continuous;
            PerformingActions = true;
            NumActionsPerformedSinceStarted = 0;
            ActionData = data;

            if (OnStartedPerformingActions != null)
            {
                OnStartedPerformingActions(this, Target, continuous);
            }

            State = ActionState.Idle;
        }

        public virtual void Stop()
        {
            PerformingActions = false;
            ContinuousActions = false;

            if (OnStoppedPerformingActions != null)
            {
                OnStoppedPerformingActions(this, NumActionsPerformedSinceStarted);
            }
        }

        public virtual void Pause()
        {
            if (Paused) return;

            Paused = true;

            if (!PerformingActions)
            {
                PerformingActions = false;
                PerformingActionsBeforePause = true;
            }
        }

        public virtual void Resume()
        {
            if (!Paused) return;

            Paused = false;

            if (PerformingActionsBeforePause)
            {
                PerformingActions = true;
            }
        }

        public abstract IAction DeepClone();

        public abstract void Update(GameTime gameTime);

        public virtual void Deserialize(XElement element)
        {
            XAttribute myName = element.Attribute("name");
            this.Name = myName != null ? myName.Value : string.Empty;
        }
    }
}
